package com.byit.face;

import com.arcsoft.face.*;
import com.arcsoft.face.enums.ImageFormat;
import com.byit.domain.SmFace;
import com.byit.domain.SmFace3DAngle;
import com.byit.domain.SmFaceInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.DataBufferByte;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

@Service
public class FaceEngineService {

    @Value("${config.freesdk.app-id}")
    private String appId;
    @Value("${config.freesdk.sdk-key}")
    private String sdkKey;

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private FaceEngine init() {
        System.out.println(appId);
        System.out.println(sdkKey);

        EngineConfiguration engineConfiguration = EngineConfiguration.builder().functionConfiguration(
                FunctionConfiguration.builder()
                        .supportAge(true)
                        .supportFace3dAngle(true)
                        .supportFaceDetect(true)
                        .supportFaceRecognition(true)
                        .supportGender(true)
                        .build()).build();
        //初始化引擎
        FaceEngine faceEngine =new FaceEngine();
        faceEngine.active(appId,sdkKey);
        faceEngine.init(engineConfiguration);
        return faceEngine;
    }

    /**
     * 获取输入图片
     *
     * @param file
     * @return
     */
    public ImageInfo getFaceFile(File file) {
        ImageInfo imageInfo = null;
        try {
            if (file == null) {
                return null;
            }

            imageInfo = getRGBData(file);

        } catch (Exception e) {
            logger.error("", e.getMessage());

        }
        return imageInfo;
    }

    /**
     * 获取人脸信息
     *
     * @param img1
     * @return
     */
    public List<SmFace> getFaceInfo(String img1) {

        FaceEngine faceEngine = init();
        ImageInfo imageInfo = getRGBData(new File(img1));
        List<FaceInfo> faceInfoList = detectFace(imageInfo);
        //性别提取
        List<GenderInfo> genderInfoList = new ArrayList<GenderInfo>();
        //年龄提取
        List<AgeInfo> ageInfoList = new ArrayList<AgeInfo>();
        //3D信息提取
        List<Face3DAngle> face3DAngleList = new ArrayList<Face3DAngle>();
        try {

            int processResult = faceEngine.process(imageInfo.getRgbData(), imageInfo.getWidth(), imageInfo.getHeight(), ImageFormat.CP_PAF_BGR24, faceInfoList, FunctionConfiguration.builder().supportAge(true).supportFace3dAngle(true).supportGender(true).build());

            int genderCode = faceEngine.getGender(genderInfoList);

            int ageCode = faceEngine.getAge(ageInfoList);

            int face3dCode = faceEngine.getFace3DAngle(face3DAngleList);
        } catch (Exception e) {
            logger.error(e.getMessage());
        }


        //  System.out.println("检测的人脸个数:" + face3DAngleList.size());
        List<SmFace> listFace = new ArrayList<SmFace>();
        if (face3DAngleList == null) {
            logger.error("无法识别人脸");
            return null;
        } else if (face3DAngleList.size() == 0) {
            logger.error("无法识别人脸");
            return null;
        }
        for (int i = 0; i < face3DAngleList.size(); i++) {

            logger.info("性别: " + genderInfoList.get(i).getGender());
            logger.info("年龄: " + ageInfoList.get(i).getAge());
            logger.info("3D角度信息：");
            logger.info("横滚角：" + face3DAngleList.get(i).getRoll());
            logger.info("偏航角：" + face3DAngleList.get(i).getYaw());
            logger.info("俯仰角：" + face3DAngleList.get(i).getPitch());
            logger.info("检测状态：" + face3DAngleList.get(i).getStatus());

            SmFace face = new SmFace();
            SmFaceInfo faceInfo = new SmFaceInfo();
            SmFace3DAngle face3DAngle = new SmFace3DAngle();
            face.setFaceNum(face3DAngleList.size());

            faceInfo.setGender(genderInfoList.get(i).getGender());
            faceInfo.setAge(ageInfoList.get(i).getAge());

            face3DAngle.setRoll(face3DAngleList.get(i).getRoll());
            face3DAngle.setYaw(face3DAngleList.get(i).getYaw());
            face3DAngle.setPitch(face3DAngleList.get(i).getPitch());
            face3DAngle.setStatus(face3DAngleList.get(i).getStatus());
            faceInfo.setFace3DAngles(face3DAngle);

            face.setFaceInfo(faceInfo);

            listFace.add(face);

        }
        return listFace;
    }

    /**
     * 人脸检测
     *
     * @param imageInfo
     * @return
     */
    private List<FaceInfo> detectFace(ImageInfo imageInfo) {

        List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
        try {
            FaceEngine faceEngine = init();

            //人脸检测
            faceEngine.detectFaces(imageInfo.getRgbData(), imageInfo.getWidth(), imageInfo.getHeight(), ImageFormat.CP_PAF_BGR24, faceInfoList);
            logger.info("检测的人脸个数:" + faceInfoList.size());
        } catch (Exception e) {
            logger.error("", e);
        }


        return faceInfoList;
    }

    /**
     * 人脸检测
     *
     * @param inputStream
     * @return
     */
    public List<FaceInfo> detectFace(InputStream inputStream) {
        List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
        try {
            ImageInfo imageInfo = getRGBData(ImageIO.read(inputStream));
            FaceEngine faceEngine = init();

            //人脸检测
            faceEngine.detectFaces(imageInfo.getRgbData(), imageInfo.getWidth(), imageInfo.getHeight(), ImageFormat.CP_PAF_BGR24, faceInfoList);
            logger.info("检测的人脸个数:" + faceInfoList.size());
        } catch (Exception e) {
            logger.error("", e);
        }


        return faceInfoList;
    }

    /**
     * 人脸比对
     *
     * @return
     */
    public String faceCompare(String img1, String img2) {

        //相识度
        FaceSimilar faceSimilar = new FaceSimilar();
        try {
            FaceEngine faceEngine = init();

            ImageInfo imageInfo1 = getRGBData(new File(img1));
            ImageInfo imageInfo2 = getRGBData(new File(img2));

            List<FaceInfo> faceInfoList1 = detectFace(imageInfo1);
            List<FaceInfo> faceInfoList2 = detectFace(imageInfo2);


            //提取人脸特征
            FaceFeature faceFeature = new FaceFeature();
            faceEngine.extractFaceFeature(imageInfo1.getRgbData(), imageInfo1.getWidth(), imageInfo1.getHeight(), ImageFormat.CP_PAF_BGR24, faceInfoList1.get(0), faceFeature);

            FaceFeature faceFeature2 = new FaceFeature();
            faceEngine.extractFaceFeature(imageInfo2.getRgbData(), imageInfo2.getWidth(), imageInfo2.getHeight(), ImageFormat.CP_PAF_BGR24, faceInfoList2.get(0), faceFeature2);

            //人脸对比
            FaceFeature targetFaceFeature = new FaceFeature();

            targetFaceFeature.setFeatureData(faceFeature.getFeatureData());

            FaceFeature sourceFaceFeature = new FaceFeature();
            sourceFaceFeature.setFeatureData(faceFeature2.getFeatureData());

            faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);

            logger.info("相识度: " + faceSimilar);
        } catch (Exception e) {

            logger.error(e.getMessage());
        }

        return faceSimilar.toString();

    }

    public float faceCompare(InputStream img1, InputStream img2) {
        //相识度
        FaceSimilar faceSimilar = new FaceSimilar();
        try {
            FaceEngine faceEngine = init();

            ImageInfo imageInfo1 = getRGBData(ImageIO.read(img1));
            ImageInfo imageInfo2 = getRGBData(ImageIO.read(img2));

            List<FaceInfo> faceInfoList1 = detectFace(imageInfo1);
            List<FaceInfo> faceInfoList2 = detectFace(imageInfo2);


            //提取人脸特征
            FaceFeature faceFeature = new FaceFeature();
            faceEngine.extractFaceFeature(imageInfo1.getRgbData(), imageInfo1.getWidth(), imageInfo1.getHeight(), ImageFormat.CP_PAF_BGR24, faceInfoList1.get(0), faceFeature);

            FaceFeature faceFeature2 = new FaceFeature();
            faceEngine.extractFaceFeature(imageInfo2.getRgbData(), imageInfo2.getWidth(), imageInfo2.getHeight(), ImageFormat.CP_PAF_BGR24, faceInfoList2.get(0), faceFeature2);

            //人脸对比
            FaceFeature targetFaceFeature = new FaceFeature();

            targetFaceFeature.setFeatureData(faceFeature.getFeatureData());

            FaceFeature sourceFaceFeature = new FaceFeature();
            sourceFaceFeature.setFeatureData(faceFeature2.getFeatureData());

            faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);

            logger.info("相识度: " + faceSimilar);
        } catch (Exception e) {

            logger.error(e.getMessage());
        }

        return faceSimilar.getScore();
    }

    public ImageInfo getRGBData(File file) {
        if (file == null) {
            return null;
        }
        ImageInfo imageInfo;
        try {
            //将图片文件加载到内存缓冲区
            BufferedImage image = ImageIO.read(file);
            imageInfo = bufferedImage2ImageInfo(image);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        return imageInfo;
    }

    public ImageInfo getRGBData(BufferedImage image) {
        if (image == null) {
            return null;
        }
        return bufferedImage2ImageInfo(image);
    }

    private ImageInfo bufferedImage2ImageInfo(BufferedImage image) {
        ImageInfo imageInfo = new ImageInfo();
        int width = image.getWidth();
        int height = image.getHeight();
        // 使图片居中
        width = width & (~3);
        height = height & (~3);
        imageInfo.width = width;
        imageInfo.height = height;
        //根据原图片信息新建一个图片缓冲区
        BufferedImage resultImage = new BufferedImage(width, height, image.getType());
        //得到原图的rgb像素矩阵
        int[] rgb = image.getRGB(0, 0, width, height, null, 0, width);
        //将像素矩阵 绘制到新的图片缓冲区中
        resultImage.setRGB(0, 0, width, height, rgb, 0, width);
        //进行数据格式化为可用数据
        BufferedImage dstImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
        if (resultImage.getType() != BufferedImage.TYPE_3BYTE_BGR) {
            ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);
            ColorConvertOp colorConvertOp = new ColorConvertOp(cs, dstImage.createGraphics().getRenderingHints());
            colorConvertOp.filter(resultImage, dstImage);
        } else {
            dstImage = resultImage;
        }

        //获取rgb数据
        imageInfo.rgbData = ((DataBufferByte) (dstImage.getRaster().getDataBuffer())).getData();
        return imageInfo;
    }


    class ImageInfo {
        public byte[] rgbData;
        public int width;
        public int height;

        public byte[] getRgbData() {
            return rgbData;
        }

        public void setRgbData(byte[] rgbData) {
            this.rgbData = rgbData;
        }

        public int getWidth() {
            return width;
        }

        public void setWidth(int width) {
            this.width = width;
        }

        public int getHeight() {
            return height;
        }

        public void setHeight(int height) {
            this.height = height;
        }
    }

}